<template>
    <div class="forbid-select console-page">
        <el-tabs v-model="activeTab" type="border-card" ref="tabRef" class="interface" v-loading="loading">
            <el-tab-pane label="接口配置" name="fix-interfaceInfo">
                <el-row style="height: 100%">
                    <el-col :span="6" class="placeholder" />
                    <el-col :span="12" style="padding-top: 15px">
                        <el-form :model="interfaceInfo" ref="interfaceInfoRef" :spellcheck="false"
                            @submit.native.prevent :rules="interfaceInfoRule">
                            <el-form-item label="名称" prop="name">
                                <el-input v-model="interfaceInfo.name" class="input-auto-resize" :spellcheck="false" />
                            </el-form-item>
                            <el-form-item label="接口地址" prop="url">
                                <el-input v-model="interfaceInfo.url" class="input-auto-resize" :spellcheck="false" />
                            </el-form-item>
                            <el-row>
                                <el-col :span="12" class="inf select">
                                    <el-form-item label="状态" prop="status">
                                        <el-radio v-model="interfaceInfo.status" :label="1">发布</el-radio>
                                        <el-radio v-model="interfaceInfo.status" :label="0">草稿</el-radio>
                                    </el-form-item>
                                </el-col>
                                <el-col :span="12" class="inf select">
                                    <el-form-item label="接口方法" prop="method">
                                        <el-radio v-model="interfaceInfo.method" label="get">GET</el-radio>
                                        <el-radio v-model="interfaceInfo.method" label="post">POST</el-radio>
                                    </el-form-item>
                                </el-col>
                            </el-row>
                            <el-row>
                                <el-col :span="12" class="inf select">
                                    <el-form-item label="数据加密" prop="status">
                                        <el-radio v-model="interfaceInfo.encrypt" :label="1">开启</el-radio>
                                        <el-radio v-model="interfaceInfo.encrypt" :label="0">关闭</el-radio>
                                    </el-form-item>
                                </el-col>
                                <el-col :span="12" class="inf select">
                                    <el-form-item label="同步请求锁" prop="requestLock">
                                        <el-radio v-model="interfaceInfo.requestLock" :label="1">开启</el-radio>
                                        <el-radio v-model="interfaceInfo.requestLock" :label="0">关闭</el-radio>
                                    </el-form-item>
                                </el-col>
                            </el-row>
                            <el-row>
                                <el-col :span="12" class="inf select">
                                    <el-form-item label="访问类型" prop="status">
                                        <el-radio v-model="interfaceInfo.apiType" :label="1">内部</el-radio>
                                        <el-radio v-model="interfaceInfo.apiType" :label="0">开放</el-radio>
                                    </el-form-item>
                                </el-col>
                                <el-col :span="12" class="inf type">
                                    <el-form-item label="返回类型" prop="returnType">
                                        <el-radio-group v-model="interfaceInfo.returnType"
                                            :disabled="disableReturnType">
                                            <el-radio value="list">List</el-radio>
                                            <el-radio value="map">Map</el-radio>
                                            <el-radio value="auto">Auto</el-radio>
                                        </el-radio-group>
                                    </el-form-item>
                                </el-col>
                            </el-row>
                            <el-row>
                                <el-col :span="12" class="inf select">
                                    <el-form-item label="权限验证" prop="checkPermission">
                                        <el-radio v-model="interfaceInfo.checkPermission" :label="1">开启</el-radio>
                                        <el-radio v-model="interfaceInfo.checkPermission" :label="0">关闭</el-radio>
                                    </el-form-item>
                                </el-col>
                                <el-col :span="12" class="inf select" v-permission.update.write.&>
                                    <el-form-item label="接口类型" prop="type">
                                        <el-radio-group v-model="interfaceInfo.type">
                                            <el-radio value="java">JAVA</el-radio>
                                            <el-radio value="sql">SQL</el-radio>
                                            <el-radio value="html">HTML</el-radio>
                                        </el-radio-group>
                                    </el-form-item>
                                </el-col>
                            </el-row>
                            <el-form-item label="缓存时间(s)" prop="useCache">
                                <el-input-number v-model="interfaceInfo.useCache" :step="30" :min="-1" :max="3600"
                                    title="" class="input-auto-resize" controls-position="right" @blur="useCacheBlur" />
                            </el-form-item>
                            <el-form-item label="分组标签" prop="group">
                                <tooltip v-model="interfaceInfo.group" class="input-auto-resize" border>
                                    <template #suffix>
                                        <el-icon class="el-input__icon" @click="showGroup = true">
                                            <component :is="getIcon('search')" />
                                        </el-icon>
                                    </template>
                                </tooltip>
                            </el-form-item>
                            <el-form-item label="接口白名单" prop="group">
                                <tooltip v-model="interfaceInfo.whiteList" class="input-auto-resize auth" border>
                                    <template #suffix>
                                        <el-icon class="el-input__icon" @click="clickWhiteList">
                                            <component :is="getIcon('search')" />
                                        </el-icon>
                                    </template>
                                </tooltip>
                            </el-form-item>
                            <el-form-item label="接口黑名单" prop="group">
                                <tooltip v-model="interfaceInfo.blackList" class="input-auto-resize auth" border>
                                    <template #suffix>
                                        <el-icon class="el-input__icon" @click="clickBlackList">
                                            <component :is="getIcon('search')" />
                                        </el-icon>
                                    </template>
                                </tooltip>
                            </el-form-item>
                            <el-form-item label="备注说明" prop="comments">
                                <el-input v-model="interfaceInfo.comments" class="input-auto-resize"
                                    :spellcheck="false" />
                            </el-form-item>
                        </el-form>
                    </el-col>
                    <el-col :span="6" class="placeholder" />
                    <el-drawer :show-close="false" size="430px" v-model="showGroup" direction="rtl"
                        class="forbid-select interface-group-drawer" append-to-body @open="openGroupDrawer"
                        @closed="closedGroupDrawer" @close="closeGroupDrawer">
                        <template #header>
                            <div>分组标签</div>
                            <el-input v-model="groupInput" class="input-auto-resize group-input" />
                            <el-button :icon="getIcon('search')" circle type="primary" plain text bg
                                class="add-group button-auto-resize" @click="searchGroupTag" />
                            <el-button :icon="getIcon('plus')" circle type="primary" plain text bg
                                class="add-group button-auto-resize" @click="addGroupTag" />
                        </template>
                        <el-row class="tag-list">
                            <el-col :span="8" v-for="(tag, index) in interfaceGroupSearch" :key="index"
                                class="tag-item">
                                <el-tag :class="getClass(tag)" v-ripple @click="select(tag)" :type="getType(tag)">
                                    {{ tag }}
                                </el-tag>
                            </el-col>
                        </el-row>
                    </el-drawer>
                    <el-drawer :show-close="false" size="430px" v-model="showAuth" direction="rtl"
                        class="forbid-select interface-group-drawer" append-to-body @open="openAuthDrawer"
                        @closed="closedAuthDrawer" @close="closeAuthDrawer">
                        <template #header>
                            <div>{{ currentAuth }}</div>
                            <el-input v-model="authInput" class="input-auto-resize group-input" />
                            <el-button :icon="getIcon('search')" circle type="primary" plain text bg
                                class="add-group button-auto-resize" @click="searchAuthList" />
                            <el-button :icon="getIcon('plus')" circle type="primary" plain text bg
                                class="add-group button-auto-resize" @click="addAuthTag" />
                        </template>
                        <el-row class="tag-list">
                            <el-col :span="8" v-for="(tag, index) in interfaceAuthListSearch" :key="index"
                                class="tag-item">
                                <el-tag :class="getClass(tag)" v-ripple @click="select(tag)" :type="getType(tag)">
                                    {{ tag }}
                                </el-tag>
                            </el-col>
                        </el-row>
                    </el-drawer>
                </el-row>
            </el-tab-pane>
            <el-tab-pane label="接口内容" name="fix-content">
                <aceEditor style="height:100%" v-model="interfaceInfo.code"
                    :options="{ lang: interfaceInfo.type, fontSize: config.fontSize }" :command="command" />
            </el-tab-pane>
            <el-tab-pane label="接口参数" name="fix-params" :disabled="disableTab">
                <el-row v-if="copyParams.params.length === 0" style="height: 100%;padding: 10px;">
                    <el-tag class="forbid-select param input-auto-resize" type="warning"
                        style="text-align: center;width: 200px!important" disable-transitions>无
                    </el-tag>
                </el-row>
                <el-row v-else style="padding: 10px;">
                    <el-col :span="paramsTagSpan" v-for="(tag, index) in copyParams.params"
                        style="padding-right: 10px;margin-bottom: 10px" :key="index">
                        <el-card :body-style="{ padding: '0px' }" shadow="hover" v-if="copyParams.type === 'sql'"
                            style="padding:15px" :class="'el-card__require_' + paramsContent[tag.name].require">
                            <div slot="header" class="e-page"
                                style="font-size: var(--fon-size);white-space: nowrap;padding-bottom: 10px;">
                                <span>{{ tag.name }}</span>
                            </div>
                            <el-form ref="baseRef" :model="paramsContent[tag.name]" :spellcheck="false"
                                @submit.native.prevent>
                                <el-form-item label="是否必选" prop="require" style="margin-bottom: 5px">
                                    <div style="width: 100%">
                                        <el-radio-group v-model="paramsContent[tag.name].require"
                                            :disabled="key.includes(tag.name)">
                                            <el-radio :value="1">必选</el-radio>
                                            <el-radio :value="2">可选</el-radio>
                                            <el-radio :value="3">自解析</el-radio>
                                        </el-radio-group>
                                    </div>
                                </el-form-item>
                                <el-form-item label="默认值" prop="content" style="margin-bottom: 5px">
                                    <el-input v-model="paramsContent[tag.name].default" class="input-auto-resize"
                                        :spellcheck="false" :disabled="key.includes(tag.name)" />
                                </el-form-item>
                                <el-form-item label="参数说明" prop="content" style="margin-bottom: 5px">
                                    <el-input v-model="paramsContent[tag.name].content" class="input-auto-resize"
                                        :spellcheck="false" :disabled="key.includes(tag.name)" />
                                </el-form-item>
                            </el-form>
                        </el-card>
                        <el-card :body-style="{ padding: '0px' }" shadow="hover" v-else
                            :class="'el-card__require_' + tag.require">
                            <div slot="header" class="e-page" style="font-size: var(--fon-size);white-space: nowrap">
                                <span>{{ tag.name }}</span>
                            </div>
                            <el-form ref="baseRef" :model="tag" :spellcheck="false" @submit.native.prevent>
                                <el-form-item label="是否必选" prop="require" style="margin-bottom: 5px">
                                    <div style="width: 100%">
                                        <el-radio v-model="tag.require" :label="1" disabled>必选</el-radio>
                                        <el-radio v-model="tag.require" :label="2" disabled>可选</el-radio>
                                    </div>
                                </el-form-item>
                                <el-form-item label="默认值" prop="content" style="margin-bottom: 5px">
                                    <el-input v-model="tag.default" class="input-auto-resize" :spellcheck="false"
                                        disabled />
                                </el-form-item>
                                <el-form-item label="参数说明" prop="content" style="margin-bottom: 5px">
                                    <el-input v-model="tag.content" class="input-auto-resize" :spellcheck="false"
                                        disabled />
                                </el-form-item>
                            </el-form>
                        </el-card>
                    </el-col>
                </el-row>
            </el-tab-pane>
            <el-tab-pane label="接口响应" name="fix-response" :disabled="disableTab">
                <interfaceResponse ref="responseRef" />
            </el-tab-pane>
            <el-tab-pane label="接口调试" name="fix-run" lazy v-if="!newInterface" :disabled="disableTab">
                <interfaceDoc :interfaceInfo="interfaceInfo" />
            </el-tab-pane>
        </el-tabs>
        <div class="tools">
            <el-button :icon="getIcon('refresh')" plain @click="getInterfaceInfo(true)" v-if="!newInterface">
                重置数据
            </el-button>
            <el-button :icon="getIcon('check')" plain @click="save" v-permission.update.write>
                保存
            </el-button>
        </div>
        <el-drawer v-model="showDrawer" direction="rtl" :show-close="false" :close-on-press-escape="false" size="60%"
            :with-header="false" @open="open" @closed="useModalSize(false)" class="interface-drawer" append-to-body>
            <aceEditor style="height: 100%;" ref="editorRef"
                :options="{ readOnly: true, lang: interfaceInfo.type, fontSize: config.fontSize }" v-model="help" />
        </el-drawer>
    </div>
</template>

<script setup>
import { deepCopy, getIcon } from "@/utils/tools"
import { useElMessage, useTabPaneAnimation, useModalSize, useRequest, useEventListener, useElMessageBox } from "@usehook"
import router from "@/router"
import { config } from "@/utils/setting"
import storeInstance from "@/pinia"

let activeTab = $ref("fix-interfaceInfo")
useTabPaneAnimation(() => activeTab, (pane) => { storeInstance.tagMenuStore.setTabPane(pane) })
let paramsContent = $ref({})
let interfaceGroup = $ref([])
let interfaceAuthList = $ref([])
let interfaceGroupSearch = $ref([])
let interfaceAuthListSearch = $ref([])
let showGroup = $ref(false)
let showAuth = $ref(false)
let groupInput = $ref("")
let authInput = $ref("")
let selectedTag = $ref([])
let interfaceInfo = $ref({
    name: '',
    url: '',
    params: [],
    comments: '',
    code: '',
    status: 0,
    sequence: null,
    method: "get",
    returnType: "auto",
    type: 'sql',
    checkPermission: 1,
    requestLock: 0,
    useCache: 0,
    apiType: 1,
    encrypt: 0,
    group: "",
    whiteList: "",
    blackList: ""
})

let currentAuth = $ref("")

let paramsTagSpan = $ref(6)
let loading = $ref(false)
let pauseParseParamsFlg = $ref(false)
let interfaceCode = $ref("")
let interfaceInfoRule = $ref({
    name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
    url: [{ required: true, message: 'url不能为空', trigger: 'blur' }]
})
let disableReturnType = $ref(false)
let newInterface = $ref(!router.currentRoute.value.query.sequence)
let showDrawer = $ref(false)
let command = {
    name: "F1",
    bindKey: { win: "F1", mac: "F1" },
    exec: () => {
        showDrawer = !showDrawer
    },
    readOnly: true
}
let help = $ref("")

const responseRef = $ref(null)
const interfaceInfoRef = $ref(null)
let disableTab = $ref(true)
let searched = $ref(false)

const searchGroupTag = () => {
    searched = !!groupInput
    interfaceGroupSearch = groupInput ? interfaceGroup.filter(item => item.indexOf(groupInput) > -1) : interfaceGroup
}

const searchAuthList = () => {
    searched = !!authInput
    interfaceAuthListSearch = authInput ? interfaceAuthList.filter(item => item.indexOf(authInput) > -1) : interfaceAuthList
}

const addGroupTag = () => {
    if (groupInput && !interfaceGroup.includes(groupInput)) interfaceGroup.push(groupInput)
    if (searched) searchGroupTag()
}

const addAuthTag = () => {
    if (authInput && !interfaceAuthList.includes(authInput)) interfaceAuthList.push(authInput)
    if (searched) searchAuthList()
}

const select = (tag) => {
    selectedTag.includes(tag) ? selectedTag.splice(selectedTag.indexOf(tag), 1) : selectedTag.push(tag)
}

const getClass = (tag) => {
    return `cursor-pointer input-auto-resize ${selectedTag.includes(tag) ? 'gradient-border' : ''}`
}
const getType = (tag) => {
    return selectedTag.includes(tag) ? 'primary' : 'info'
}

const useCacheBlur = () => {
    interfaceInfo.useCache = interfaceInfo.useCache || 0
}

const copyParams = $computed(() => {
    return deepCopy(interfaceInfo)
})

const openGroupDrawer = () => {
    useModalSize()
    searchGroupTag()
    if (interfaceInfo.group) selectedTag = interfaceInfo.group.split(",")
}

const openAuthDrawer = () => {
    useModalSize()
    searchAuthList()
    const list = interfaceInfo[currentAuth === '接口白名单' ? 'whiteList' : 'blackList']
    if (list) selectedTag = list.split(",")
}

const closedGroupDrawer = () => {
    useModalSize(false)
    groupInput = ""
    searched = false
}

const closeGroupDrawer = () => {
    interfaceInfo.group = selectedTag.sort().join(',')
    selectedTag = []
}

const closedAuthDrawer = () => {
    useModalSize(false)
    authInput = ""
    searched = false
}

const closeAuthDrawer = () => {
    interfaceInfo[currentAuth === '接口白名单' ? 'whiteList' : 'blackList'] = selectedTag.sort().join(',')
    selectedTag = []
}

const clickWhiteList = () => {
    showAuth = true
    currentAuth = "接口白名单"
}

const clickBlackList = () => {
    showAuth = true
    currentAuth = "接口黑名单"

}

const open = () => {
    useModalSize()
    if (interfaceInfo.type === 'java') {
        help = "package cn.dansj.handler.interfaces;\n" +
            "\n" +
            "import cn.dansj.annotation.InterfaceParam;\n" +
            "import cn.dansj.annotation.MarkAsApi;\n" +
            "import cn.dansj.common.utils.database.DBUtils;\n" +
            "import cn.dansj.handler.InterfaceHandler;\n" +
            "import cn.dansj.utils.interfaces.CallStatement;\n" +
            "import org.springframework.dao.DataAccessException;\n" +
            "import org.springframework.jdbc.core.CallableStatementCallback;\n" +
            "import org.springframework.jdbc.core.CallableStatementCreator;\n" +
            "import org.springframework.lang.NonNull;\n" +
            "\n" +
            "import java.sql.CallableStatement;\n" +
            "import java.sql.Connection;\n" +
            "import java.sql.ResultSet;\n" +
            "import java.sql.SQLException;\n" +
            "import java.util.*;\n" +
            "\n" +
            "/**\n" +
            " * 接口信息(interfaceInfoService)                   cn.dansj.common.service.InterfaceInfoService interfaceInfoService\n" +
            " * Redis工具类(redisUtils)                          cn.dansj.common.utils.redis.RedisUtils redisUtils\n" +
            " * 接口库jdbc(jdbcTemplate)                         org.springframework.jdbc.core.JdbcTemplate jdbcTemplate\n" +
            " * 获取bean工具类                                   cn.dansj.common.utils.context.ApplicationContextProvider\n" +
            " * 获取环境变量工具类                                cn.dansj.common.utils.context.GetEnvironment\n" +
            " * DB工具类                                         cn.dansj.common.utils.database.DBUtils\n" +
            " * 参数注解(value,require,comment,defaultValue)     cn.dansj.annotation.InterfaceParam\n" +
            " */\n" +
            "\n" +
            "/*\n" +
            "create or replace procedure prc_out(val        varchar2,\n" +
            "                                    out_var  out sys_refcursor,\n" +
            "                                    out_var2 out sys_refcursor) as\n" +
            "  v_sql  varchar2(2000);\n" +
            "  v_sql2 varchar2(2000);\n" +
            "\n" +
            "begin\n" +
            "  v_sql  := 'select ' || val || ' t from dual';\n" +
            "  v_sql2 := 'select 999 t from dual union all select 9999 t from dual';\n" +
            "  dbms_output.put_line(v_sql);\n" +
            "  open out_var for v_sql;\n" +
            "  open out_var2 for v_sql2;\n" +
            "\n" +
            "end;\n" +
            "* */\n" +
            "\n" +
            "@SuppressWarnings(\"all\")\n" +
            "@MarkAsApi\n" +
            "public class GroovyInterfaceHandler extends InterfaceHandler {\n" +
            "\n" +
            "    static class StatementCallable implements CallableStatementCreator {\n" +
            "        private final Map<String, Object> requestMap;\n" +
            "\n" +
            "        StatementCallable(Map<String, Object> requestMap) {\n" +
            "            this.requestMap = requestMap;\n" +
            "        }\n" +
            "\n" +
            "        @Override\n" +
            "        @NonNull\n" +
            "        public CallableStatement createCallableStatement(Connection con) throws SQLException {\n" +
            "            String storedProc = \"call prc_out(?, ?, ?)\";// 调用的sql\n" +
            "            CallableStatement cs = con.prepareCall(storedProc);\n" +
            "            cs.setString(1, requestMap.get(\"val\").toString());\n" +
            "            cs.registerOutParameter(2, CallStatement.getType(\"cursor\"));// 注册输出参数的类型\n" +
            "            cs.registerOutParameter(3, CallStatement.getType(\"cursor\"));// 注册输出参数的类型\n" +
            "            return cs;\n" +
            "        }\n" +
            "    }\n" +
            "\n" +
            "    static class CallableCallback<T> implements CallableStatementCallback<T> {\n" +
            "        @Override\n" +
            "        public T doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {\n" +
            "            cs.execute();\n" +
            "            Map<String, List<Map<String, Object>>> output = new HashMap<>();\n" +
            "            List<Integer> cursorIndex = Arrays.asList(2, 3);\n" +
            "            for (int cursor : cursorIndex) {\n" +
            "                ResultSet rs = (ResultSet) cs.getObject(cursor);// 获取游标一行的值\n" +
            "                List<Map<String, Object>> resultsMap = DBUtils.resultSetToJson(rs);\n" +
            "                output.put(\"cursor_\" + cursor, resultsMap);\n" +
            "                rs.close();\n" +
            "            }\n" +
            "            return (T) output;\n" +
            "        }\n" +
            "    }\n" +
            "\n" +
            "    @InterfaceParam(value = \"val\", require = true, comment = \"val\")\n" +
            "    public Object execute(Map<String, Object> paramsMap) {\n" +
            "        return jdbcTemplate.execute(new StatementCallable(paramsMap), new CallableCallback<>());\n" +
            "    }\n" +
            "}"
    } else {
        help = "/*interface标签引用其他接口,ref指向对应的接口的名称,解析后标签会被替换为对应接口所有的SQL*/\n" +
            "<interface ref='interfaceName'/> \n\n" +
            "select 1 column1,'2' column2 from dual t;\n\n" +
            "/*变量的使用同mybatis\n允许多段SQL,前面几段作为参数处理使用,保证结果只有一行,返回值会被最后一段SQL作为入参参数*/\n" +
            "select #{column1} c_1,'${column2}' c_2 from dual t"
    }
}

const getInterfaceInfo = (reset) => {
    const route = router.currentRoute.value;
    const sequence = route.query.sequence;
    useRequest({ url: "/interface/detail", sequence: sequence, loadingMessage: "正在加载接口数据", loadingTarget: ".console-page" }).then(resData => {
        if (resData && resData.status) {
            const data = resData.data;
            if (data) {
                paramsContent = JSON.parse(data.params || '{}');
                interfaceInfo.name = data.interfaceName;
                interfaceInfo.code = data.code;
                interfaceInfo.status = data.status;
                interfaceInfo.sequence = data.sequence;
                interfaceInfo.method = data.method;
                interfaceInfo.comments = data.comments;
                interfaceInfo.url = data.url
                interfaceInfo.returnType = data.returnType;
                interfaceInfo.type = data.type;
                interfaceInfo.checkPermission = data.checkPermission
                interfaceInfo.requestLock = data.requestLock
                interfaceInfo.encrypt = data.encrypt
                interfaceInfo.useCache = data.useCache
                interfaceInfo.apiType = data.apiType
                disableTab = interfaceInfo.type && interfaceInfo.type === 'html'
                interfaceInfo.group = data.inGroup
                interfaceInfo.whiteList = data.whiteList
                interfaceInfo.blackList = data.blackList
                if (interfaceCode !== data.code && reset) {
                    activeTab = 'fix-content'
                }
                interfaceCode = data.code
                nextTick(() => { responseRef.set(data.response) })
            }
        }
    })
}

watch(() => interfaceInfo, (info) => {
    const isHtml = info.type === "html"
    const isNotNesting = info.code.replaceAll(" ", "").includes("@MarkAsApi(nestingInMap=false)")
    disableReturnType = isHtml || isNotNesting
    if (disableReturnType && interfaceInfo.returnType !== 'auto') {
        interfaceInfo.returnType = "auto"
        if (isHtml) useElMessage.warning("HTML类接口，返回类型已调整为auto")
        if (isNotNesting) useElMessage.warning("MarkAsApi注解的nestingInMap参数为false，接口返回类型已调整为auto")
    }
}, { deep: true, immediate: true })

const save = async () => {
    let rej = false;
    await interfaceInfoRef.validate((valid) => {
        if (!valid) {
            activeTab = 'fix-interfaceInfo'
            rej = true;
        }
    });
    if (rej) return

    let codeEmpty = !interfaceInfo.code;
    let matchDDL = interfaceInfo.code.match(/([ ]+|^|\n)(insert|delete|update|create|drop|exec|begin|merge|declare|truncate|grant|commit|rollback|alter|audit|connect|disconnect|exit|noaudit|quit|revoke|rename|set|add|references|foreign)([ ]+|$|\n)/g);
    if (codeEmpty) {
        activeTab = 'fix-content';
        useElMessage.error("接口内容不能为空")
        rej = true;
    }
    if (rej) return

    if (matchDDL && interfaceInfo.type.toLowerCase() === 'sql') {
        activeTab = 'fix-content';
        useElMessage.error("禁用保留关键字：" + matchDDL)
        rej = true;
    }
    if (rej) return

    const response = responseRef.save()
    for (let resp of response) {
        if (!resp.name || !resp.type || !resp.comment) {
            activeTab = 'fix-response'
            rej = true;
            useElMessage.error("存在未编辑完成的项, 完善或删除后在提交")
        }
    }
    if (rej) return

    const rejIndex = responseRef.checkDupIndex()
    if (rejIndex) {
        activeTab = 'fix-response'
        useElMessage.error("存在相同名称的项:" + rejIndex + ", 请调整后保存")
        return
    }

    if (rej) return

    if (checkUnexpect(interfaceInfo.code) && interfaceInfo.type === 'sql') {
        useModalSize()
        activeTab = 'fix-content';
        await useElMessageBox('提示', '代码中存在非变量引用$或#的内容，是否继续提交?', {
            showClose: false, showCancelButton: true
        }).then(() => {
            confirmSave(response);
        }).finally(() => {
            useModalSize(false)
        });
    } else {
        confirmSave(response)
    }
    newInterface = !router.currentRoute.value.query.sequence
}

const confirmSave = (response) => {
    loading = true
    useRequest.post("/interface/save", {
        ...interfaceInfo, response: JSON.stringify(response),
        //返回原始的代码作为比对
        originalInterfaceCode: interfaceCode
    }).then((resData) => {
        if (resData && resData.status) {
            //保存成功把原始的代码更新为最新的
            interfaceCode = interfaceInfo.code;
            const sequence = resData.data;

            const index = router.currentRoute.value.path + "?sequence=" + sequence
            storeInstance.tagMenuStore.updateTagMenuTitle(router.currentRoute.value.fullPath, interfaceInfo.comments || interfaceInfo.name, index)
            interfaceInfo.sequence = sequence;
            useElMessage("保存成功")
            if (newInterface) router.push(index);

        } else if (resData && resData.message) {
            useElMessage.error(resData.message)
        }
    }).then(() => {
        loading = false
    });
}

const parseParam = (val) => {
    let allParamsMatch = val.replace(/\/\*.*?\*\//g, "").replace(/--.*/g, '').match(/(\$|\#)\{.*?}/g) || []
    let allParams = []
    for (let p of allParamsMatch) {
        let param = p.split(',')[0].replace("$", "").replace("#", "").replace("{", "").replace("}", "").replace(",", "");
        let outMode = /mode[ ]*=[ ]*(OUT|out)/g.test(p)

        if (param !== null && param !== "" && !outMode) {
            allParams.push(param)
        }
    }

    // let allParamsMatch = val.replace(/\/\*.*?\*\//g, "").replace(/--.*/g, '').match(/(\$|\#)\{.*?(\}|,)/g) || []
    // let allParams = []
    // for (let p of allParamsMatch) {
    //   let param = p.replace("$", "").replace("#", "").replace("{", "").replace("}", "").replace(",", "");
    //   if (param !== null && param !== "") {
    //     allParams.push(param)
    //   }
    // }

    return allParams;
    // if (this.interfaceInfo.type === 'sql') {
    //
    // } else {
    //   let params = []
    //   for (let param of val.match(/@InterfaceParam\((.*?)\)/g)) {
    //     for (let value of param.match(/".*?"/g)) {
    //       params.push(value.replaceAll('"', ''))
    //     }
    //   }
    //   return params;
    // }
}

const checkUnexpect = (val) => {
    return val.replace(/\/\*.*?\*\//g, "").replace(/--.*/g, '').replace(/'.*?'/g, '').replace(/(\$|\#)\{.*?\}/g, '').match(/(\$|\#|\{|\}).*?/g) || val.match(/(\$|\#)\{(\}|,)/g)
}

const getJavaParams = (val) => {
    interfaceInfo.params = []
    for (let param of val.match(/@InterfaceParam\((.*?)"[ ]*\)/g) || []) {
        let value;
        if (param.indexOf('value') === -1) {
            value = param.match(/"(.*?)"/)
        } else {
            value = param.match(/value[ ]*=[ ]*"(.*?)"/)
        }

        let require = param.match(/require[ ]*=[ ]*(.*?)[,\\)]/)
        let comment = param.match(/comment[ ]*=[ ]*"(.*?)"/)
        let defaultValue = param.match(/defaultValue[ ]*=[ ]*"(.*?)"/)
        interfaceInfo.params.push({
            name: value && value.length > 1 ? value[1] : "",
            require: require && require.length > 1 ? require[1] === "true" ? 1 : 2 : 2,
            content: comment && comment.length > 1 ? comment[1] : "",
            default: defaultValue && defaultValue.length > 1 ? defaultValue[1] : ""
        })
    }
}

let key = $ref([])

const parseParams = (val) => {
    if (val) {
        interfaceInfo.params = []

        if (interfaceInfo.type === 'sql') {
            let params = Array.from((new Set(parseParam(val))))
            //判断解析的参数是否在paramsContent中
            for (let p of params) {
                if (Object.keys(paramsContent).includes(p)) {
                    interfaceInfo.params.push(paramsContent[p])
                } else {
                    const inKey = key.includes(p)
                    let param = { name: p, require: inKey ? 3 : 2, content: inKey ? "关键字参数，接口自动解析" : "", default: "" };
                    interfaceInfo.params.push(param);
                    paramsContent[p] = param;
                }
            }
        } else {
            getJavaParams(val)
        }

    } else {
        interfaceInfo.params = []
    }
}

const keyMap = (e) => {
    let { key, keyCode, ctrlKey, altKey } = e;
    if ((key === 'KeyS' || keyCode === 83) && (ctrlKey || altKey)) {
        e.preventDefault(); //关闭浏览器快捷键
        document.activeElement.blur()
        save()
    }

    if ((key === 'F1' || keyCode === 112) && activeTab === 'fix-content') {
        showDrawer = !showDrawer;
    }
}

onMounted(() => {
    loading = true;
    try {
        if (!newInterface) getInterfaceInfo();
    } finally {
        loading = false
    }

    useRequest({ url: "/interface/key" }).then(resp => {
        if (resp && resp.status) key = resp.data
    })

    useRequest("/interface/group").then((resp) => {
        if (resp && resp.status) interfaceGroup = resp.data
    })

    useRequest("/interface/authList").then((resp) => {
        if (resp && resp.status) interfaceAuthList = resp.data
    })
})

useEventListener('keydown', keyMap)

watch(() => interfaceInfo.code, (newVal) => {
    if (!pauseParseParamsFlg) {
        pauseParseParamsFlg = true;
        parseParams(newVal)
        pauseParseParamsFlg = false;
    }
})
</script>

<style scoped>
/*表单样式*/
:deep(.el-form-item label) {
    line-height: 30px;
}

:deep(.el-form-item__content) {
    line-height: 24px;
    font-size: 13px;
}

:deep(.history .el-form-item__content) {
    margin-top: 3px;
}

:deep(.el-form-item__error) {
    padding-top: 1px;
}

:deep(.el-form-item) {
    margin-bottom: 15px;
}

/*错误提示信息位置*/
:deep(.el-form .el-form-item__error) {
    top: 26%;
    right: 10px;
    left: unset;
    font-size: calc(var(--font-size) - 4px);
}

:deep(.ace_editor) {
    margin-top: 0;
}

:deep(.el-message.is-closable .el-message__content) {
    padding-right: 25px !important;
}

:deep(.tools) {
    position: absolute;
    right: 5px;
    top: 8px;
}

:deep(.tools .el-button) {
    font-family: var(--font-family);
    font-weight: var(--font-weight);
}

:deep(.el-button [class*=el-icon-] + span) {
    margin-left: 1px;
}

:deep(.el-select .el-input.is-focus .el-input__inner) {
    -moz-user-select: none !important;
    /*火狐*/
    -webkit-user-select: none !important;
    /*webkit浏览器*/
    -ms-user-select: none !important;
    /*IE10*/
    -khtml-user-select: none !important;
    /*早期浏览器*/
    user-select: none !important;
}

:deep(.el-tag) {
    width: 100%;
}

:deep(.input-new-tag) {
    width: 100%;
    vertical-align: bottom;
    padding-right: 2px
}

:deep(.button-new-tag) {
    height: 24px;
    line-height: 22px;
    width: 100%;
    min-width: 40px;
    margin-right: 0;
}

:deep(.param.el-tag) {
    margin-right: 3px !important;
}

:deep(.button-new-tag.el-tag--small) {
    padding: 0 5px;
}

:deep(.el-input.is-disabled .el-input__inner) {
    color: #606266;
    cursor: default;
}

:deep(.el-input.is-disabled .el-input__icon) {
    cursor: default;
}

:deep(.java) {
    margin: 10px 0 5px 0 !important
}

:deep(.el-radio__label) {
    font-size: var(--font-size);
}

:deep(.el-popover.el-poper .el-row form.el-form .el-form-item) {
    margin-bottom: 10px !important;
}

:deep(.el-dialog__body) {
    padding: 5px 10px;
}

:deep(.el-radio) {
    margin-right: 20px !important;
    width: 60px
}

:deep(.el-cascader-node > .el-radio),
:deep(.el-radio:last-child) {
    margin-right: 0 !important;
}

:deep(.el-card__header) {
    padding: 10px 10px;
}

:deep(.el-card__body .el-form-item) {
    margin-bottom: 5px !important;
}

:deep(.el-card__body) {
    padding: 10px;
    height: fit-content;
}

:deep(.el-card) {
    border-radius: 3px;
    padding: 10px;
}

:deep(.el-card__require_3) {
    background-color: #f4f4f5;
    border-color: #e9e9eb;
    color: #909399;
}

:deep(.el-card__require_2) {
    background-color: #fdf6ec;
    border-color: #faecd8;
    color: #e6a23c;
}

:deep(.el-card__require_1) {
    background-color: #fef0f0;
    border-color: #fde2e2;
    color: #f56c6c;
}

:deep(.el-dialog__footer) {
    border-top: 1px solid #EBEEF5;
    padding: 10px 20px;
}

:deep(.select .el-form-item__content .el-radio:last-child) {
    margin-right: 0 !important;
}

:deep(.history .el-scrollbar__wrap) {
    overflow-x: hidden;
}

:deep([id*='fix-'] .el-form-item label) {
    line-height: calc(var(--font-size) * 2);
    font-size: var(--font-size);
}

:deep(.el-tab-pane) {
    height: 100%;
}

:deep(.el-col) {
    height: fit-content;
    width: fit-content;
}

:deep(.el-form-item__label) {
    width: 120px;
}

.interface-group-drawer .el-tag+.el-tag {
    margin-left: 10px;
}
</style>

<style>
.interface-drawer .el-drawer__header {
    margin-bottom: 0 !important;
    padding: 16px 10px;
    font-size: 25px;
}

.interface-drawer .el-drawer__body {
    padding: 0 5px 5px 5px;
}

/* 使用:not(:first-child)选择器配合父级的子元素选择器 */
.tag-list>.tag-item:not(:nth-child(3n+1)) {
    padding-left: 5px;
    /* 每一行的第一个元素之外都设置左边距 */
}

.tag-list .tag-item {
    padding-top: 5px;
}

.tag-list .tag-item:nth-child(-n+3) {
    padding-top: 0;
}

.group-input {
    width: 220px !important;
    padding: 0 10px;
}

.interface-group-drawer .el-drawer__header>:first-child {
    flex: unset;
}

.interface .el-tabs__item.is-disabled {
    display: none;
}

.interface .e-tooltip .disabled-style {
    color: #434343;
}

.interface .auth.e-tooltip .disabled-style {
    color: #c30000e8;
}
</style>